package org.ttitfly.workflow.engine.basic;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.ttitfly.workflow.Session;
import org.ttitfly.workflow.SessionHolder;
import org.ttitfly.workflow.engine.Action;
import org.ttitfly.workflow.engine.Activity;
import org.ttitfly.workflow.engine.Process;
import org.ttitfly.workflow.engine.TaskRunUnit;
import org.ttitfly.workflow.engine.assignment.Assignment;
import org.ttitfly.workflow.engine.decider.Decider;
import org.ttitfly.workflow.engine.run.Task;
import org.ttitfly.workflow.exception.PermissionNotAllowedException;
import org.ttitfly.workflow.exception.ProcessDefineException;
import org.ttitfly.workflow.exception.ProcessRunException;
import org.ttitfly.workflow.handler.Handler;


/**
 * 活动的基本功能实现
 * 
 * @author 潘海春
 * @version 2009-9-18
 */
public class BasicActivity extends TaskRunUnit implements Activity {

	/**
	 * 默认action
	 */
	private Action defaultAction;

	/**
	 * actions
	 */
	private Map<String, Action> actions = new HashMap<String, Action>();

	/**
	 * 任务分配
	 */
	private Assignment assignment;

	/**
	 * 权限决策者
	 */
	private Decider permissionDecider;

	/**
	 * 构造函数
	 * 
	 * @param parent
	 * @param name
	 * @param defaultAction
	 * @param actions
	 * @param assignment
	 * @param permissionDecider
	 * @param activeHandlers
	 * @param closeHandlers
	 */
	public BasicActivity(Process parent, String name, Action defaultAction,
			List<Action> actions, Assignment assignment,
			Decider permissionDecider, List<Handler> activeHandlers,
			List<Handler> closeHandlers) {
		super(parent, name, activeHandlers, closeHandlers);
		if (defaultAction == null && (actions == null || actions.isEmpty())) {
			throw new IllegalArgumentException("参数[defaultAction,actions]至少有一个不能为空！");
		}
		this.defaultAction = defaultAction;
		if (defaultAction != null) {
			putAction(defaultAction.getName(), defaultAction);
		}
		if (actions != null) {
			for (Action action : actions) {
				putAction(action.getName(), action);
			}
		}
		this.assignment = assignment;
		this.permissionDecider = permissionDecider;
	}

	/**
	 * 放置action
	 * 
	 * @param name
	 * @param action
	 */
	protected void putAction(String name, Action action) {
		if (this.actions.containsKey(name)) {
			throw new ProcessDefineException("流程[" + parent.getName() + "."
					+ parent.getVersion() + "]的[" + name + "]活动已经存在一个名称为["
					+ action.getName() + "]的动作！");
		} else {
			this.actions.put(action.getName(), action);
		}
	}

	@Override
	protected void onActive() throws Exception {
		super.onActive();
		if (assignment != null) {
			// 得到被分配到任务的人员
			String[] assigners = assignment.assign();
			if (assigners != null && assigners.length > 0) {
				StringBuilder sb = new StringBuilder();
				// 将分配到任务的人员标识用逗号隔开拼装起来
				for (String assigner : assigners) {
					if (assigner != null && !"".equals(assigner)) {
						sb.append(assigner).append(",");
					}
				}
				if (sb.length() > 0) {
					sb.deleteCharAt(sb.length() - 1);
				}
				SessionHolder.currentSession().currentTask().setAssigners(sb.toString());
			}
		}
	}

	@Override
	public void execute() throws ProcessRunException {
		if (!isRunning()) {
			throw new ProcessRunException("当前状态必须为[RUNNING]才能被执行！");
		}
		if (defaultAction == null) {
			throw new ProcessRunException("没有找到默认动作来执行！");
		}
		execute(defaultAction);
	}

	@Override
	public void execute(String actionName) throws ProcessRunException {
		if (actionName == null || "".equals(actionName)) {
			throw new ProcessRunException("参数[actionName]不能为空！");
		}
		if (!isRunning()) {
			throw new ProcessRunException("当前状态必须为[RUNNING]才能被执行！");
		}
		Action action = actions.get(actionName);
		if (action == null) {
			throw new ProcessRunException("没有找到名称为[" + actionName + "]的动作！");
		}
		execute(action);
	}

	/**
	 * 执行action
	 * 
	 * @param action
	 * @throws ProcessRunException
	 */
	protected void execute(Action action) throws ProcessRunException {
		if (permissionDecider != null && !permissionDecider.decide()) {
			throw new PermissionNotAllowedException();
		}
		String nextUnitName = action.execute();
		Session session = SessionHolder.currentSession();
		Task task = session.currentTask();
		task.setAction(action.getName());
		task.setRemark((String) session.getVariable(TASK_REMARK_KEY));
		task.setActionStatus(action.getStatus());
		close();
		if (nextUnitName == null || "".equals(nextUnitName)) {
			parent.checkComplete();
		} else {
			parent.dispatch(nextUnitName);
		}
	}
}
